package com.uinnova.product.eam.service.impl;

import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.BinaryException;
import com.binary.core.lang.StringUtils;
import com.binary.core.util.BinaryUtils;
import com.binary.framework.exception.ServiceException;
import com.binary.jdbc.Page;
import com.google.common.collect.Lists;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.AssetAttrDataScreen;
import com.uinnova.product.eam.comm.model.es.EamCategory;
import com.uinnova.product.eam.comm.model.es.EamDiagramRelationSys;
import com.uinnova.product.eam.config.Env;
import com.uinnova.product.eam.model.*;
import com.uinnova.product.eam.model.asset.EamCiRltCopyDTO;
import com.uinnova.product.eam.model.asset.EamCiRltCopyResult;
import com.uinnova.product.eam.model.asset.EamCopyRltVO;
import com.uinnova.product.eam.model.dto.CheckCIAttr;
import com.uinnova.product.eam.model.enums.ArtifactType;
import com.uinnova.product.eam.model.vo.CiClassLimitUseDetail;
import com.uinnova.product.eam.model.vo.ESAttrAggScreenBean;
import com.uinnova.product.eam.service.*;
import com.uinnova.product.eam.service.asset.AssetContent;
import com.uinnova.product.eam.service.asset.BmConfigSvc;
import com.uinnova.product.eam.service.es.IamsESCmdbCommDesignSvc;
import com.uinnova.product.vmdb.comm.bean.CIState;
import com.uinnova.product.vmdb.comm.model.ci.CCcCi;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.comm.model.ci.CcCi;
import com.uinnova.product.vmdb.comm.model.ci.CcCiAttrDef;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.project.api.diagram.v2.client.ESDiagramApiClient;
import com.uino.api.client.cmdb.ICIClassApiSvc;
import com.uino.bean.cmdb.base.*;
import com.uino.bean.cmdb.query.ClsAttrQueryGroup;
import com.uino.bean.cmdb.query.ESAttrBean;
import com.uino.bean.cmdb.query.ESCISearchBean;
import com.uino.dao.cmdb.ESCIClassSvc;
import com.uino.dao.cmdb.ESDirSvc;
import com.uino.util.sys.CheckAttrUtil;
import com.uino.util.sys.SysUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * eam的ci服务层实现
 *
 * @author lichong
 * @version 2020-8-10
 */
@Service
public class EamCiSvcImpl implements IEamCiSvc, AssetContent {
    @Autowired
    private ICISwitchSvc iciSwitchSvc;
    @Autowired
    private ICIClassApiSvc iciClassApiSvc;
    @Resource
    private EamCategorySvc categorySvc;
    @Resource
    private ESDiagramApiClient esDiagramApiClient;
    @Autowired
    private IEamArtifactSvc eamArtifactSvc;
    @Autowired
    private IEamArtifactColumnSvc artifactColumnSvc;
    @Resource
    private BmConfigSvc bmConfigSvc;
    @Resource
    private EamModelSvc modelSvc;
    @Resource
    private IamsCIRltPrivateSvc rltPrivateSvc;
    @Resource
    private ESDirSvc esDirSvc;
    @Autowired
    private EamDiagramRelationSysService diagramRelationSysService;
    @Autowired
    private CiClassLimitUseSvc ciClassLimitUseSvc;
    private static final String DISPLAY_NAME = "[\"数据字典\"]";
    private static final String DISPLAY_CONFIG = "DISPLAY_CONFIG";

    @Autowired
    @Lazy
    IamsESCmdbCommDesignSvc commSvc;

    @Resource
    AssetAttrDataScreenSvc assetAttrDataScreenSvc;

    @Resource
    ESCIClassSvc esClsSvc;


    @Override
    public List<VcCiClassInfoDto> queryCiCountByClass(CiQueryCdtExtend cdt, LibType libType) {
        ESCISearchBean searchBean = new ESCISearchBean();
        if (!BinaryUtils.isEmpty(cdt.getLike())) {
            List<String> words = new ArrayList<>();
            words.add(cdt.getLike());
            searchBean.setWords(words);
        }
        Set<Long> classIdSet = null;
        Map<Long, String> filterMap = null;
        // 获取制品绑定资产所有分类和筛选数据
        if (!BinaryUtils.isEmpty(cdt.getViewType()) && !cdt.getViewType().equals("0") && BinaryUtils.isEmpty(cdt.getClassId()) && BinaryUtils.isEmpty(cdt.getClassIds())) {
            Long artifactId = Long.valueOf(cdt.getViewType());
            List<EamArtifactElementVo> elementList = artifactColumnSvc.queryByArtifactId(artifactId, Lists.newArrayList(ArtifactType.ASSET_TYPE.val()));
            if (!BinaryUtils.isEmpty(elementList)) {
                classIdSet = new HashSet<>();
                filterMap = new HashMap<>();
                for (EamArtifactElementVo artifactElementVo : elementList) {
                    List<String> elements = artifactElementVo.getElements();
                    for (String element : elements) {
                        EamArtifactCiVo vo = JSON.parseObject(element, EamArtifactCiVo.class);
                        if (BinaryUtils.isEmpty(vo.getType()) || !vo.getType().equals("class") || !vo.getAssetsFlag()) {
                            continue;
                        }
                        classIdSet.add(Long.valueOf(vo.getId()));
                        // 制品绑定资产的筛选数据
                        if (!StringUtils.isEmpty(vo.getFilter()) && JSONArray.parseArray(vo.getFilter()).size() > 0) {
                            filterMap.put(Long.valueOf(vo.getId()), vo.getFilter());
                        }
                    }
                }
                cdt.setClassIds(classIdSet.toArray(new Long[0]));
            }
        }

        List<Long> classIdList = null;
        if (!CollectionUtils.isEmpty(classIdSet)) {
            classIdList = new ArrayList<>(classIdSet);
        } else {
            if (cdt.getClassIds() != null && cdt.getClassIds().length > 0) {
                classIdList = Arrays.asList(cdt.getClassIds());
            }
        }

        // 制品图控制没有classId不展示分类，自由视图不控制
        List<VcCiClassInfoDto> retList = new LinkedList<>();
        if (classIdList == null && !Objects.equals(cdt.getViewType(), "0")) {
            return retList;
        }

        Map<Long, Long> ciNumMap = this.getFilterCiCount(searchBean, cdt, libType, classIdList, filterMap);
        if (!BinaryUtils.isEmpty(searchBean.getClassIds())) {
            for (Long classId : searchBean.getClassIds()) {
                if (!ciNumMap.containsKey(classId)) {
                    ciNumMap.put(classId, 0L);
                }
            }
        }
        Set<Long> classIds = ciNumMap.keySet();
        List<CcCiClassInfo> ciClassInfoList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(classIds)) {
            CCcCiClass classCdt = new CCcCiClass();
            classCdt.setIds(classIds.toArray(new Long[0]));
            ciClassInfoList = iciClassApiSvc.queryClassByCdt(classCdt);
        }

        if (!BinaryUtils.isEmpty(cdt.getLike()) && cdt.getViewType().equals("0")) {
            CCcCiClass classCdtByName = new CCcCiClass();
            classCdtByName.setClassName(cdt.getLike());
            classCdtByName.setIds(classIds.toArray(new Long[classIds.size()]));
            List<CcCiClassInfo> ciClassByNameList = iciClassApiSvc.queryClassByCdt(classCdtByName);
            if (!BinaryUtils.isEmpty(ciClassByNameList)) {
                List<Long> queryClassIds = ciClassByNameList.stream().map(item -> item.getCiClass().getId()).collect(Collectors.toList());
                ESCISearchBean queryBean = new ESCISearchBean();
                Map<Long, Long> queryMap = this.getFilterCiCount(queryBean, cdt, libType, queryClassIds, filterMap);
                for (CcCiClassInfo info : ciClassByNameList) {
                    if (classIds.contains(info.getCiClass().getId()) || queryMap.get(info.getCiClass().getId()) == null || queryMap.get(info.getCiClass().getId()) == 0){
                        continue;
                    }
                    ciClassInfoList.add(info);
                    ciNumMap.put(info.getCiClass().getId(), queryMap.get(info.getCiClass().getId()));
                }
            }
        }


        Map<Long, Long> limitUseCiNumMap = new HashMap<>();
        Map<Long, ESCISearchBean> needReSearchBeanMap = new HashMap<>();
        Set<Long> artifactClassIds = getArtifactClassIds(cdt);
        if (!StringUtils.isBlank(cdt.getDiagramId()) && !CollectionUtils.isEmpty(artifactClassIds)) {
            //制品下的分类有无限制引用
            List<CiClassLimitUseDetail> limitUseDetails = ciClassLimitUseSvc.details(artifactClassIds);
            Map<Long, CiClassLimitUseDetail> limitUseDetailMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(limitUseDetails)) {
                limitUseDetailMap = limitUseDetails.stream().filter(CiClassLimitUseDetail::getLimitUse)
                        .collect(Collectors.toMap(CiClassLimitUseDetail::getCiClassId, Function.identity()));
            }
            //视图绑定资产
            EamDiagramRelationSys diagramRelationSys = diagramRelationSysService.getEamDiagramRelationSys(cdt.getDiagramId());
            if (diagramRelationSys != null && !StringUtils.isBlank(diagramRelationSys.getEsSysId())) {
                String diagramBindAssertCiCode = diagramRelationSys.getEsSysId();
                //绑定资产分类
                List<ESCIInfo> bindCiInfos = iciSwitchSvc.getCiByCodes(
                        Arrays.asList(diagramBindAssertCiCode), null, LibType.DESIGN);
                if (!CollectionUtils.isEmpty(bindCiInfos)) {
                    ESCIInfo bindCiInfo = bindCiInfos.get(0);
                    for (Long artifactClassId : artifactClassIds) {
                        if (!limitUseDetailMap.containsKey(artifactClassId)) {
                            continue;
                        }
                        CiClassLimitUseDetail detail = limitUseDetailMap.get(artifactClassId);
                        if (detail.getRelateClassId().equals(bindCiInfo.getClassId())) {
                            List<CcCiAttrDef> limitAttrDefs = detail.getLimitAttrDefs();
                            ESCISearchBean reSearchBean = EamUtil.copy(searchBean, ESCISearchBean.class);
                            reSearchBean.setClassIds(Arrays.asList(artifactClassId));
                            List<ESAttrBean> orAttrs = new ArrayList<>();
                            for (CcCiAttrDef limitAttrDef : limitAttrDefs) {
                                ESAttrBean orAttr = new ESAttrBean();
                                orAttr.setKey(limitAttrDef.getProName());
                                orAttr.setOptType(2);
                                orAttr.setValue("\"ciCode\":\""+diagramBindAssertCiCode+"\"");
                                orAttrs.add(orAttr);
                            }
                            reSearchBean.setOrAttrs(orAttrs);
                            needReSearchBeanMap.put(artifactClassId, reSearchBean);
                        }
                    }
                }
            }
            if (!BinaryUtils.isEmpty(needReSearchBeanMap)) {
                for (ESCISearchBean needReSearchBean : needReSearchBeanMap.values()) {
                    Map<Long, Long> needReSearchCiNumMap = iciSwitchSvc.countCiNumGroupClsByQuery(needReSearchBean, libType);
                    limitUseCiNumMap.putAll(needReSearchCiNumMap);
                }
            }
        }

        List<Long> displayDomain = this.getDisplayDomain();

        //强制隐藏的分类：
        //国投需求：【编辑器】内，左侧私有库tab内，不展示【系统】分类数据；即：系统分类数据，只支持在设计库拖拽使用
        // https://www.tapd.cn/65990798/prong/stories/view/1165990798001129553?from_iteration_id=1165990798001004445
        List<String> ignoreCiClassCodes = cdt.getIgnoreCiClassCodes();
        if (ignoreCiClassCodes == null) {
            ignoreCiClassCodes = new ArrayList<>();
        }

        for (CcCiClassInfo ciClassInfo : ciClassInfoList) {
            if(displayDomain.contains(ciClassInfo.getCiClass().getDirId())
                    || ignoreCiClassCodes.contains(ciClassInfo.getCiClass().getClassCode())){
                continue;
            }
            VcCiClassInfoDto classInfoDto = new VcCiClassInfoDto();
            classInfoDto.setCiClass(ciClassInfo.getCiClass());
            classInfoDto.setAttrDefs(ciClassInfo.getAttrDefs());
            Long ciClassId = ciClassInfo.getCiClass().getId();
            if (needReSearchBeanMap.containsKey(ciClassId)) {
                classInfoDto.setCiCount(limitUseCiNumMap.getOrDefault(ciClassId, 0L));
            } else {
                classInfoDto.setCiCount(ciNumMap.get(ciClassInfo.getCiClass().getId()));
            }
            retList.add(classInfoDto);
        }
        return retList;
    }

    @Override
    public Page<CcCiInfo> getAttrValuesBySearchBean(ESAttrAggScreenBean bean) {
        ESCISearchBean searchBean = new ESCISearchBean();
        searchBean.setPageNum(bean.getPageNum());
        searchBean.setPageSize(bean.getPageSize());
        if (!BinaryUtils.isEmpty(bean.getLike())) {
            searchBean.setWords(Lists.newArrayList(bean.getLike()));
        }
        if (!BinaryUtils.isEmpty(bean.getAttrName()) && !BinaryUtils.isEmpty(bean.getLike())) {
            List<ESAttrBean> andAttrs = new ArrayList<>();
            ESAttrBean attrBean = new ESAttrBean();
            attrBean.setKey(bean.getAttrName());
            attrBean.setValue(bean.getLike());
            attrBean.setOptType(2);
            andAttrs.add(attrBean);
            searchBean.setAndAttrs(andAttrs);
        }
        if (!BinaryUtils.isEmpty(bean.getAttrNames())&&!BinaryUtils.isEmpty(bean.getLike())) {
            List<ESAttrBean> orAttrs = new ArrayList<>();
            for (String attrName : bean.getAttrNames()) {
                ESAttrBean attrBean = new ESAttrBean();
                attrBean.setKey(attrName);
                attrBean.setValue(bean.getLike());
                attrBean.setOptType(2);
                orAttrs.add(attrBean);
            }
            searchBean.setOrAttrs(orAttrs);
        }
        //根据属性Id属性信息得到属性名称
        CcCiClassInfo ccCiClassInfo = esClsSvc.queryClassInfoById(bean.getClassId());
        Assert.notNull(ccCiClassInfo, "分类不存在");
        Long classId = ccCiClassInfo.getCiClass().getId();
        searchBean.setClassIds(Lists.newArrayList(classId));

        Map<Long, String> attrDefMap = ccCiClassInfo.getAttrDefs().stream().collect(Collectors.toMap(CcCiAttrDef::getId, e -> e.getProName(), (k1, k2) -> k1));
        if (!BinaryUtils.isEmpty(bean.getBindId())) {
            AssetAttrDataScreen dateScreenInfo = assetAttrDataScreenSvc.getDateScreenInfo(bean.getBindId(), bean.getClassId());
            if (!BinaryUtils.isEmpty(dateScreenInfo) && CollectionUtils.isNotEmpty(dateScreenInfo.getScreenInfo())) {
                List<ClsAttrQueryGroup> orClsAttrQueryGroups = new ArrayList<>();
                for (List<JSONObject> list : dateScreenInfo.getScreenInfo()) {
                    ClsAttrQueryGroup filterGroup = new ClsAttrQueryGroup();
                    List<ESAttrBean> andAttrs = new ArrayList<>();
                    for (JSONObject json : list) {
                        long key = json.getLongValue("key");
                        String ccCiAttrDef = attrDefMap.get(key);
                        if (!BinaryUtils.isEmpty(ccCiAttrDef)) {
                            ESAttrBean esAttrBean = new ESAttrBean();
//                            throw new BinaryException("属性不存在,classId:" + bean.getClassId() + ",attrId:" + key);
                            esAttrBean.setKey(ccCiAttrDef);
                            esAttrBean.setValue(json.getString("value"));
                            esAttrBean.setOptType(json.getIntValue("optType"));
                            andAttrs.add(esAttrBean);
                        }
                    }
                    filterGroup.setClassId(classId);
                    if (!CollectionUtils.isEmpty(andAttrs)) {
                        filterGroup.setAndAttrs(andAttrs);
                    }
                    orClsAttrQueryGroups.add(filterGroup);
                }
                searchBean.setOrClsAttrQueryGroups(orClsAttrQueryGroups);
            }

        }
        // 临时库查询（草稿及审批中） 设计库查询（已发布，变更中，作废中）
//        ArrayList<ESAttrBean> orAttrs = new ArrayList<>();
//
//        ESAttrBean esAttrBean = new ESAttrBean();
//        esAttrBean.setOptType(1);
//        esAttrBean.setKey(RELEASE_STATE);
//        esAttrBean.setValue(RELEASE);
//        orAttrs.add(esAttrBean);
//        ESAttrBean esAttrBean2 = new ESAttrBean();
//        esAttrBean2.setOptType(1);
//        esAttrBean2.setKey(RELEASE_STATE);
//        esAttrBean2.setValue(CHANGING);
//        orAttrs.add(esAttrBean2);
//        ESAttrBean esAttrBean3 = new ESAttrBean();
//        esAttrBean3.setOptType(1);
//        esAttrBean3.setKey(RELEASE_STATE);
//        esAttrBean3.setValue(CANCELLING);
//        orAttrs.add(esAttrBean3);
//
//        if (!CollectionUtils.isEmpty(orAttrs)) {
//            searchBean.setOrAttrs(orAttrs);
//        }
        Page<ESCIInfo> esciInfoPage = iciSwitchSvc.searchESCIByBean(searchBean,LibType.DESIGN);

        Page<CcCiInfo> result = new Page<>();
        result.setPageNum(esciInfoPage.getPageNum());
        result.setPageSize(esciInfoPage.getPageSize());
        result.setTotalPages(esciInfoPage.getTotalPages());
        result.setTotalRows(esciInfoPage.getTotalRows());
        List<ESCIInfo> data = esciInfoPage.getData();
        data = data.stream().filter(e -> !CANCELLED.equals(e.getAttrs().get(RELEASE_STATE))).collect(Collectors.toList());
        List<CcCiInfo> ciInfos = commSvc.transEsInfoList(data, true);
        result.setData(ciInfos);
        return result;
    }


    private Set<Long> getArtifactClassIds(CiQueryCdtExtend cdt) {
        if (StringUtils.isBlank(cdt.getDiagramId())
                || StringUtils.isBlank(cdt.getViewType())
                || cdt.getViewType().equals("0")) {
            return new HashSet<>();
        }
        Set<Long> artifactClassIds = new HashSet<>();
        Long artifactId = Long.valueOf(cdt.getViewType());
        List<EamArtifactElementVo> elementList = artifactColumnSvc.queryByArtifactId(artifactId, Lists.newArrayList(ArtifactType.ASSET_TYPE.val()));
        if (BinaryUtils.isEmpty(elementList)) {
            return artifactClassIds;
        }
        for (EamArtifactElementVo artifactElementVo : elementList) {
            List<String> elements = artifactElementVo.getElements();
            for (String element : elements) {
                EamArtifactCiVo vo = JSON.parseObject(element, EamArtifactCiVo.class);
                if (BinaryUtils.isEmpty(vo.getType()) || !vo.getType().equals("class") || !vo.getAssetsFlag()) {
                    continue;
                }
                artifactClassIds.add(Long.valueOf(vo.getId()));
            }
        }
        return artifactClassIds;
    }

    /**
     * 资产库可见->筛选条件数据量
     * @param cdt
     * @param libType
     * @return
     */
    private Map<Long, Long> getFilterCiCount(ESCISearchBean searchBean, CiQueryCdtExtend cdt, LibType libType, List<Long> classIdList, Map<Long, String> filterMap) {
        if (!BinaryUtils.isEmpty(cdt.getOwnerCode())) {
            searchBean.setOwnerCode(cdt.getOwnerCode());
        }
        Map<Long, Long> ciNumMap = new HashMap<>();
        if (filterMap != null && filterMap.keySet().size() > 0 && Objects.equals(libType, LibType.DESIGN)) {
            Long[] allAssetsClass = cdt.getClassIds();
            for (Map.Entry<Long, String> filterInfo : filterMap.entrySet()) {
                List<Long> classList = new ArrayList<>(1);
                classList.add(filterInfo.getKey());
                cdt.setClassIds(classList.toArray(new Long[0]));
                ESCISearchBean filterSearch = new ESCISearchBean();
                BeanUtils.copyProperties(searchBean, filterSearch);
                filterSearch.setClassIds(classList);
                // 获取过滤条件
                String filterStr = filterInfo.getValue();
                if (!StringUtils.isEmpty(filterStr)) {
                    JSONArray jsonArray = JSONArray.parseArray(filterStr);
                    if (jsonArray.size() > 0) {
                        List<ESCIInfo> allClassCiList = new ArrayList<>();
                        for (int i = 0; i < jsonArray.size(); i++) {
                            JSONArray jsonArr = jsonArray.getJSONArray(i);
                            List<ESAttrBean> andAttrs = new ArrayList<>();
                            for (int j = 0; j < jsonArr.size(); j++) {
                                JSONObject filterJson = jsonArr.getJSONObject(j);
                                if (filterJson != null && !StringUtils.isEmpty(filterJson.getString("name"))
                                        && !StringUtils.isEmpty(filterJson.getString("value"))) {
                                    ESAttrBean esAttrBean = new ESAttrBean();
                                    esAttrBean.setKey(filterJson.getString("name"));
                                    esAttrBean.setOptType(1);
                                    esAttrBean.setValue(filterJson.getString("value"));
                                    andAttrs.add(esAttrBean);
                                }
                            }
                            filterSearch.setAndAttrs(andAttrs);
                            //处理业务组件侧边栏的过滤
                            List<String> filterModulePrimaryKeys = filterModuleClassCount(cdt, libType);
                            filterSearch.setCiPrimaryKeys(filterModulePrimaryKeys);
                            filterSearch.setPageSize(3000);
                            Page<ESCIInfo> esciInfoPage = iciSwitchSvc.searchESCIByBean(filterSearch, libType);
                            if (esciInfoPage != null){
                                if (esciInfoPage.getTotalRows() > 3000) {
                                    filterSearch.setPageSize((int)esciInfoPage.getTotalRows());
                                    esciInfoPage = iciSwitchSvc.searchESCIByBean(filterSearch, libType);
                                }
                                if(esciInfoPage != null && !CollectionUtils.isEmpty(esciInfoPage.getData())) {
                                    List<ESCIInfo> ciList = esciInfoPage.getData();
                                    allClassCiList.addAll(ciList);
                                }
                            }
                        }
                        // ci去重
                        if (!CollectionUtils.isEmpty(allClassCiList)) {
                            Set<String> ciCodeSet = allClassCiList.stream().filter(ci -> !StringUtils.isEmpty(ci.getCiCode()))
                                    .map(ci -> ci.getCiCode()).collect(Collectors.toSet());
                            ciNumMap.put(filterInfo.getKey(), (long)ciCodeSet.size());
                        }
                    }
                }
            }
            if (!Objects.equals(allAssetsClass.length, filterMap.keySet().size())) {
                List<Long> notClassList = new ArrayList<>();
                Set<Long> filterClass = filterMap.keySet();
                for (Long classId : allAssetsClass) {
                    if (!filterClass.contains(classId)) {
                        notClassList.add(classId);
                    }
                }
                if (!CollectionUtils.isEmpty(notClassList)) {
                    //处理业务组件侧边栏的过滤
                    ESCISearchBean notClassSearch = new ESCISearchBean();
                    BeanUtils.copyProperties(searchBean, notClassSearch);
                    notClassSearch.setClassIds(notClassList);
                    cdt.setClassIds(notClassList.toArray(new Long[notClassList.size()]));
                    List<String> filterModulePrimaryKeys = filterModuleClassCount(cdt, libType);
                    notClassSearch.setCiPrimaryKeys(filterModulePrimaryKeys);
                    Map<Long, Long> ciMap = iciSwitchSvc.countCiNumGroupClsByQuery(notClassSearch, libType);
                    ciNumMap.putAll(ciMap);
                }
            }
        } else {
            if (!CollectionUtils.isEmpty(classIdList)) {
                searchBean.setClassIds(classIdList);
            }
            //处理业务组件侧边栏的过滤
            List<String> filterModulePrimaryKeys = filterModuleClassCount(cdt, libType);
            searchBean.setCiPrimaryKeys(filterModulePrimaryKeys);
            ciNumMap = iciSwitchSvc.countCiNumGroupClsByQuery(searchBean, libType);
        }
        return ciNumMap;
    }

    private List<String> filterModuleClassCount(CiQueryCdtExtend cdt, LibType libType) {
        if(BinaryUtils.isEmpty(cdt.getViewType()) || BinaryUtils.isEmpty(cdt.getClassIds()) || !libType.equals(LibType.PRIVATE)){
            return Collections.emptyList();
        }
        EamArtifactVo eamArtifactVo = eamArtifactSvc.queryArtifact(Long.valueOf(cdt.getViewType()));
        JSONObject componentConfig = bmConfigSvc.getBusComponentConfig();
        if (BinaryUtils.isEmpty(eamArtifactVo)||BinaryUtils.isEmpty(componentConfig)) {
            return Collections.emptyList();
        }
        String definition = componentConfig.getString(Env.COMPONENT_DEFINITION_DIAGRAM);
        String domainRlt = componentConfig.getString(Env.DOMAIN_COMPONENT_RLT_DIAGRAM);
        boolean hasName = !eamArtifactVo.getArtifactName().equals(definition) && !eamArtifactVo.getArtifactName().equals(domainRlt);
        if(BinaryUtils.isEmpty(definition) || BinaryUtils.isEmpty(domainRlt) || hasName){
            return Collections.emptyList();
        }
        //过滤掉私有库中设计库不存在的对象
        ESCISearchBean filterBean = new ESCISearchBean();
        if (!BinaryUtils.isEmpty(cdt.getOwnerCode())) {
            filterBean.setOwnerCode(cdt.getOwnerCode());
        }
        filterBean.setClassIds(Arrays.asList(cdt.getClassIds()));
        filterBean.setPageSize(3000);
        Page<ESCIInfo> designCiPage = iciSwitchSvc.searchESCIByBean(filterBean, LibType.DESIGN);
        List<String> result = new ArrayList<>();
        if (!BinaryUtils.isEmpty(designCiPage.getData())) {
            result = designCiPage.getData().stream().map(CcCi::getCiPrimaryKey).distinct().collect(Collectors.toList());
        }
        if (CollectionUtils.isEmpty(result)) {
            result.add(Env.COMPONENT_DEFINITION_DIAGRAM + Env.DOMAIN_COMPONENT_RLT_DIAGRAM);
        }
        return result;
    }

    /**
     * 根据ci分类名称获取全部的ci信息
     *
     * @param ciClassName ci类型名称
     * @param libType     库类型
     * @return ci信息
     */
    @Override
    public List<CcCiInfo> getCiInfoListByClassName(String ciClassName, LibType libType) {
        CCcCiClass cdt = new CCcCiClass();
        cdt.setClassNameEqual(ciClassName);
        List<CcCiClassInfo> ccCiClassInfos = iciClassApiSvc.queryClassByCdt(cdt);
        return getCcCiInfos(libType, ccCiClassInfos);
    }

    private List<CcCiInfo> getCcCiInfos(LibType libType, List<CcCiClassInfo> ccCiClassInfos) {
        if (CollectionUtils.isEmpty(ccCiClassInfos)) {
            return new ArrayList<>(0);
        }
        Long ciClassId = ccCiClassInfos.get(0).getCiClass().getId();
        CCcCi ciCdt = new CCcCi();
        ciCdt.setClassId(ciClassId);
        return iciSwitchSvc.queryCiInfoList(SysUtil.getCurrentUserInfo().getDomainId(), ciCdt, null, false, false, libType);
    }

    @Override
    public List<CcCiInfo> getCiInfoListByClassCode(String ciClassCode, LibType libType) {
        CCcCiClass cdt = new CCcCiClass();
        cdt.setClassCodeEqual(ciClassCode);
        List<CcCiClassInfo> ccCiClassInfos = iciClassApiSvc.queryClassByCdt(cdt);
        return getCcCiInfos(libType, ccCiClassInfos);
    }

    @Override
    public long enableRemoveCiFromView(List<String> ciCodes, String diagramId, String ownerCode, LibType libType) {
        EamCategory parentNode = categorySvc.selectByDiagramId(diagramId, ownerCode, libType);
        if(parentNode == null){
            throw new BinaryException("当前视图对应节点信息未找到");
        }
        if(!BinaryUtils.isEmpty(parentNode.getCiCode()) && ciCodes.contains(parentNode.getCiCode())){
            throw new BinaryException("继承节点不可删除");
        }
        List<EamCategory> categoryList = categorySvc.selectListByCiCodes(parentNode.getModelId(), ciCodes, ownerCode, libType);
        if(BinaryUtils.isEmpty(categoryList)){
            return 0L;
        }
        for (EamCategory category : categoryList) {
            Long count = esDiagramApiClient.getCountByDirId(category.getId(), 1);
            if (count != null && count > 0) {
                return count;
            }
        }
        return 0L;
    }


    @Override
    public Map<Long, String> checkCiAttrs(CheckCIAttr checkCIAttr) {
        ESCISearchBean bean = new ESCISearchBean();
        bean.setIds(checkCIAttr.getIds());
        bean.setPageNum(1);
        bean.setPageSize(bean.getIds().size());
        Page<ESCIInfo> page = iciSwitchSvc.searchESCIByBean(bean, checkCIAttr.getLibType());
        if (!BinaryUtils.isEmpty(page.getData())) {
            Map<Long, String> errMap = new HashMap<>();
            Set<Long> classIds = page.getData().stream().map(ESCIInfo::getClassId).collect(Collectors.toSet());
            CCcCiClass cdt = new CCcCiClass();
            cdt.setIds(classIds.toArray(new Long[0]));
            List<CcCiClassInfo> ccCiClassInfos = iciClassApiSvc.queryClassByCdt(cdt);
            Map<Long, CcCiClassInfo> classMap = ccCiClassInfos.stream().collect(Collectors.toMap(each -> each.getCiClass().getId(), each -> each, (k1, k2) -> k2));
            for (ESCIInfo ci : page.getData()) {
                List<CcCiAttrDef> defs = classMap.get(ci.getClassId()).getAttrDefs();
                Map<String, Integer> errorMsgs = CheckAttrUtil.validateAttrValType(defs, coverToAttrs(ci.getAttrs()));
                if (BinaryUtils.isEmpty(errorMsgs)) {
                    continue;
                }
                errMap.put(ci.getId(), errorMsgs.keySet().stream().collect(Collectors.joining("|")));
            }
            return errMap;
        }
        return Collections.emptyMap();
    }


    private Map<String, String> coverToAttrs(Map<String, Object> attrs) {
        Map<String, String> newAttrs = new HashMap<>();
        if (BinaryUtils.isEmpty(attrs)) {
            return newAttrs;
        }
        attrs.forEach((k, v) -> {
            if (!BinaryUtils.isEmpty(v)) {
                newAttrs.put(k, String.valueOf(v));
            }
        });
        return newAttrs;
    }

    @Override
    public Integer handleCiExist(List<Long> ids, LibType libType, String ownerCode) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new ServiceException("ci对象主键列表不能为空!");
        }
        if (libType == null) {
            throw new ServiceException("数据库分类标识不能为空!");
        }
        if (StringUtils.isEmpty(ownerCode)) {
            throw new ServiceException("创建者标识不能为空!");
        }
        return iciSwitchSvc.handleCiExist(ids, libType, ownerCode);
    }

    @Override
    public List<String> queryValues(QueryCiValueRequest request) {
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        ESCISearchBean bean = new ESCISearchBean();
        bean.setPageSize(3000);
        bean.setPageNum(1);
        bean.setDomainId(domainId);
        bean.setClassIds(Collections.singletonList(request.getClassId()));
        Page<ESCIInfo> esCiInfoPage = iciSwitchSvc.searchESCIByBean(bean, LibType.DESIGN);

        if (esCiInfoPage.getTotalRows() == 0) {
            return Collections.emptyList();
        }
        String attrName = request.getAttrName();
        List<String> data = esCiInfoPage.getData().stream()
                .map(esCiInfo -> getValueByAttrName(attrName, esCiInfo))
                .distinct()
                .collect(Collectors.toList());

        data.removeIf(org.apache.commons.lang3.StringUtils::isBlank);
        return data;
    }

    private String getValueByAttrName(String attrName, ESCIInfo esciInfo) {
        Object value = esciInfo.getAttrs().get(attrName);
        return Objects.toString(value, "");
    }

    @Override
    public EamCiRltCopyResult copyCiAndRltBatch(EamCiRltCopyDTO params) {
        Map<String, ? extends SaveBatchCIContext> contextMap = iciSwitchSvc.copyCiListByIds(params.getCiList(), params.getOwnerCode(), params.getLibType(), params.getPostfix());
        List<ESCIInfo> dbCiList = contextMap.values().stream().map(SaveBatchCIContext::getEsCi).collect(Collectors.toList());
        List<Long> classIds = dbCiList.stream().map(ESCIInfo::getClassId).distinct().collect(Collectors.toList());
        List<ESCIClassInfo> classList = iciClassApiSvc.queryESClassInfoByIds(classIds);
        Map<Long, ESCIClassInfo> classMap = classList.stream().collect(Collectors.toMap(ESCIClassInfo::getId, each -> each));
        modelSvc.createModelCategory(params.getDiagramId(), dbCiList, params.getOwnerCode(), params.getLibType());
        EamCiRltCopyResult result = new EamCiRltCopyResult();
        Map<String, CcCiInfo> ciMap = new HashMap<>();
        for (ESCIInfo esciInfo : dbCiList) {
            ESCIClassInfo classInfo = classMap.get(esciInfo.getClassId());
            CcCiInfo ciInfo = EamUtil.coverESCIInfo(esciInfo, EamUtil.copy(classInfo.getAttrDefs(), CcCiAttrDef.class), classInfo);
            CiInfoExtend extendCi = EamUtil.copy(ciInfo, CiInfoExtend.class);
            SaveBatchCIContext context = contextMap.get(esciInfo.getCiCode());
            extendCi.setOriginId(context.getOriginCiId());
            extendCi.setOriginCiCode(context.getOriginCiCode());
            result.getCiList().add(extendCi);
            ciMap.put(extendCi.getOriginCiCode(), extendCi);
        }
        if(CollectionUtils.isEmpty(params.getRltList())){
            return result;
        }
        List<ESCIRltInfo> rltList = new ArrayList<>();
        //copy出的新关系标识-原关系标识
        Set<String> oldRltCodes = new HashSet<>();
        for (EamCopyRltVO each : params.getRltList()) {
            String key = "UK_" + each.getSourceCiCode() + "_" + each.getClassId() + "_" + each.getTargetCiCode();
            oldRltCodes.add(key);
        }
        List<ESCIRltInfo> oldRltList = rltPrivateSvc.getRltByUniqueCodes(oldRltCodes, params.getOwnerCode());
        Map<String, ESCIRltInfo> oldRltMap = oldRltList.stream().collect(Collectors.toMap(ESCIRltInfo::getUniqueCode, e -> e, (k1, k2) -> k2));
        Map<String, String> rltKeyMap = new HashMap<>();
        for (EamCopyRltVO rltVO : params.getRltList()) {
            CcCiInfo sourceCi = ciMap.get(rltVO.getSourceCiCode());
            CcCiInfo targetCi = ciMap.get(rltVO.getTargetCiCode());
            ESCIRltInfo rltInfo = new ESCIRltInfo();
            String key = sourceCi.getCi().getCiCode() + "_" + rltVO.getClassId() + "_" + targetCi.getCi().getCiCode();
            rltInfo.setCiCode(key);
            rltInfo.setClassId(rltVO.getClassId());
            rltInfo.setUniqueCode("UK_" + key);
            rltInfo.setSourceCiCode(sourceCi.getCi().getCiCode());
            rltInfo.setSourceClassId(sourceCi.getCi().getClassId());
            rltInfo.setTargetCiCode(targetCi.getCi().getCiCode());
            rltInfo.setTargetClassId(targetCi.getCi().getClassId());
            String oldUniqueCode = "UK_" + rltVO.getSourceCiCode() + "_" + rltVO.getClassId() + "_" + rltVO.getTargetCiCode();
            ESCIRltInfo oldRlt = oldRltMap.get(oldUniqueCode);
            rltInfo.setAttrs(BinaryUtils.isEmpty(oldRlt.getAttrs())?new HashMap<>():oldRlt.getAttrs());
            rltKeyMap.put(rltInfo.getUniqueCode(), oldUniqueCode);
            rltList.add(rltInfo);
        }
        rltPrivateSvc.bindBatchCiRlt(rltList, params.getOwnerCode());
        List<ESCIRltInfo> rltInfoList = rltPrivateSvc.getRltByUniqueCodes(rltKeyMap.keySet(), params.getOwnerCode());
        for (ESCIRltInfo rltInfo : rltInfoList) {
            rltInfo.setOriginCode(rltKeyMap.get(rltInfo.getUniqueCode()));
            result.getRltList().add(rltInfo);
        }
        return result;
    }

    @Override
    public List<Long> getDisplayDomain(){
        String configJson = bmConfigSvc.getConfigType(DISPLAY_CONFIG);
        if(BinaryUtils.isEmpty(configJson)){
            configJson = DISPLAY_NAME;
        }
        List<String> dirNames = JSON.parseArray(configJson, String.class);
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery("dirName.keyword", dirNames));
        List<CcCiClassDir> dirList = esDirSvc.getListByQuery(query);
        if(CollectionUtils.isEmpty(dirList)){
            return Collections.emptyList();
        }
        return dirList.stream().map(CcCiClassDir::getId).collect(Collectors.toList());
    }

    @Override
    public Boolean checkPrimaryKey(String ciCode, String ownerCode) {
        List<ESCIInfo> ciList = iciSwitchSvc.getCiByCodes(Collections.singletonList(ciCode), ownerCode, LibType.PRIVATE);
        return !BinaryUtils.isEmpty(ciList) && ciList.get(0).getState() != CIState.CREATE_INIT.val();
    }
}
